package com.xh3140.android.widget.chart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;

import androidx.annotation.ColorInt;
import androidx.annotation.Px;

import com.xh3140.android.widget.chart.scales.AxisScales;
import com.xh3140.android.widget.utils.PaintUtils;

/**
 * 坐标系基类
 * 实现了基本规范
 * 管理属性的配置
 * 绘制坐标系
 */
@SuppressWarnings("unused")
public class BaseCoordinatesView extends AbstractCoordinatesView {
    // 坐标系区域
    protected final RectF mMainRectF = new RectF(0f, 0f, 0f, 0f);

    // 坐标系绘制区域
    protected final RectF mDrawRectF = new RectF(0f, 0f, 0f, 0f);

    // 锚点坐标(动态)
    private float mAnchorX = Float.NaN;
    private float mAnchorY = Float.NaN;

    // 映射集合
    //private val mMappingSet: MutableSet<Mapping> = LinkedHashSet()

    // 坐标轴和刻度画笔
    private final Paint mPaintAxis = new Paint(Paint.ANTI_ALIAS_FLAG);

    // 网格线画笔
    private final Paint mPaintGrids = new Paint(Paint.ANTI_ALIAS_FLAG);

    // 坐标轴标签文本画笔
    private final Paint mPaintAxisLabel = new Paint(Paint.ANTI_ALIAS_FLAG);

    // 坐标轴刻度标签文本画笔
    private final TextPaint mPaintScalesLabel = new TextPaint(Paint.ANTI_ALIAS_FLAG);

    public BaseCoordinatesView(Context context) {
        super(context);
    }

    public BaseCoordinatesView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BaseCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public BaseCoordinatesView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    /**
     * AXIS 坐标轴画笔
     * GRIDS 坐标网格画笔
     * AXIS_LABEL 坐标轴标签画笔
     * SCALE_LABEL 坐标轴刻度标签画笔
     */
    protected enum PaintType {AXIS, GRIDS, AXIS_LABEL, SCALE_LABEL}

    /**
     * 配置画笔属性
     *
     * @param type 画笔类型 [PaintType]
     */
    private void configPaint(PaintType type) {
        switch (type) {
            case AXIS:
                mPaintAxis.setColor(mAxisColor);
                mPaintAxis.setStrokeWidth(mAxisThickness);
                mPaintAxis.setStyle(Paint.Style.STROKE);
                break;
            case GRIDS:
                mPaintGrids.setColor(mGridsColor);
                mPaintGrids.setStrokeWidth(mGridsThickness);
                mPaintGrids.setStyle(Paint.Style.STROKE);
                break;
            case AXIS_LABEL:
                mPaintAxisLabel.setColor(mAxisLabelTextColor);
                mPaintAxisLabel.setTextSize(mAxisLabelTextSize);
                mPaintAxisLabel.setTypeface(mAxisLabelTypeface);
                break;
            case SCALE_LABEL:
                mPaintScalesLabel.setColor(mAxisScalesLabelTextColor);
                mPaintScalesLabel.setTextSize(mAxisScalesLabelTextSize);
                mPaintScalesLabel.setTypeface(mAxisScalesLabelTypeface);
                break;
        }
    }

    @Override
    protected float getCanvasX(float x) {
        return mAnchorX + (x - mAxisScalesX.getInitial()) * mGridsBasicX / mAxisScalesX.interval;
    }

    @Override
    protected float getCanvasY(float y) {
        return mAnchorY - (y - mAxisScalesY.getInitial()) * mGridsBasicY / mAxisScalesY.interval;
    }

    @Override
    protected float getCoordinatesX(float x) {
        return mAxisScalesX.getInitial() + (x - mAnchorX) * mAxisScalesX.interval / mGridsBasicX;
    }

    @Override
    protected float getCoordinatesY(float y) {
        return mAxisScalesY.getInitial() - (y - mAnchorY) * mAxisScalesY.interval / mGridsBasicY;
    }

    @Override
    protected boolean onScaleGesture(float focusX, float focusY, float factory) {
        // 焦点不在坐标系内
        if (focusX < mMainRectF.left || focusX > mMainRectF.right || focusY < mMainRectF.top || focusY > mMainRectF.bottom) {
            return false;
        }
        // 已缩至最小
        if (factory < 1f && (mGridsBasicX < 25f || mGridsBasicY < 25f)) {
            return false;
        }
        // 已放至最大
        if (factory > 1f && ((mGridsBasicX > mMainRectF.right - mMainRectF.left) && (mGridsBasicY > mMainRectF.bottom - mMainRectF.top))) {
            return false;
        }
        // 缩放操作
        mGridsBasicX *= factory;
        mGridsBasicY *= factory;
        // 根据缩放焦点调整锚点坐标
        mAnchorX = focusX + (mAnchorX - focusX) * factory;
        mAnchorY = focusY + (mAnchorY - focusY) * factory;
        invalidate();
        return true;
    }

    @Override
    protected boolean onScrollGesture(float startX, float startY, float distanceX, float distanceY) {
        // 起点不在坐标系内
        if (startX < mMainRectF.left || startX > mMainRectF.right || startY < mMainRectF.top || startY > mMainRectF.bottom) {
            return false;
        }
        // 在X轴活动范围内
        if (distanceX < 0 && getCanvasX(mAxisScalesX.start) - mGridsBasicX < mMainRectF.right) {
            mAnchorX -= distanceX;
        } else if (distanceX > 0 && getCanvasX(mAxisScalesX.getEnd()) + mGridsBasicX > mMainRectF.left) {
            mAnchorX -= distanceX;
        }
        // 在Y轴活动范围内
        if (distanceY < 0 && getCanvasY(mAxisScalesY.getEnd()) - mGridsBasicY < mMainRectF.bottom) {
            mAnchorY -= distanceY;
        } else if (distanceY > 0 && getCanvasY(mAxisScalesY.start) + mGridsBasicY > mMainRectF.top) {
            mAnchorY -= distanceY;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 配置画笔
        configPaint(PaintType.AXIS);
        configPaint(PaintType.GRIDS);
        configPaint(PaintType.AXIS_LABEL);
        configPaint(PaintType.SCALE_LABEL);
        // 确定X范围
        final int index = mAxisScalesY.index - 1;
        final int count = (int) Math.ceil(getHeight() / mGridsBasicY + 1);
        final int leftMaxWidth = mAxisScalesY.getMaximumWidth(mPaintScalesLabel, index, index + count);
        mMainRectF.left = getPaddingLeft() + leftMaxWidth + 30f;
        mMainRectF.right = getWidth() - getPaddingRight() - PaintUtils.getTextBoundsWidth(mPaintAxisLabel, mAxisLabelX) - 30f;
        if (Float.isNaN(mAnchorX)) {
            mAnchorX = mMainRectF.left + 0.5f * mGridsBasicX;
        }
        // 确定Y范围
        mMainRectF.top = getPaddingTop() + PaintUtils.getFontMaximumHeight(mPaintAxisLabel) + 30f;
        mMainRectF.bottom = getHeight() - getPaddingBottom() - PaintUtils.getFontMaximumHeight(mPaintScalesLabel) - 30f;
        if (Float.isNaN(mAnchorY)) {
            mAnchorY = mMainRectF.bottom - 0.5f * mGridsBasicY;
        }
        // 网格区域
        mDrawRectF.left = mMainRectF.left;
        mDrawRectF.top = mMainRectF.top + 25f;
        mDrawRectF.right = mMainRectF.right - 25f;
        mDrawRectF.bottom = mMainRectF.bottom;
    }

    @Override
    protected void onThreadDraw(Canvas canvas) {
        measureLeftAreaWidth();
        drawAxisX(canvas);
        drawAxisY(canvas);
        drawGridsX(canvas);
        drawGridsY(canvas);
        //drawMapping(canvas)  ;
    }

    private void measureLeftAreaWidth() {
        // 计算最小X值，随界面滑动，这个值可能是不断变化的（Y轴刻度标签的宽度会变化）
        final int times = (int) Math.ceil((mAnchorY - mMainRectF.bottom) / mGridsBasicY);
        final int index = mAxisScalesY.index + times;
        final int count = (int) Math.ceil(getHeight() / mGridsBasicY + 1);
        final int leftMaxWidth = mAxisScalesY.getMaximumWidth(mPaintScalesLabel, index, index + count);
        mMainRectF.left = getPaddingLeft() + leftMaxWidth + 30f;
        mDrawRectF.left = mMainRectF.left;
    }

    /**
     * 绘制X坐标轴
     */
    private void drawAxisX(Canvas canvas) {
        // X轴线
        canvas.drawLine(mMainRectF.left, mMainRectF.bottom, mMainRectF.right, mMainRectF.bottom, mPaintAxis);
        // X轴箭头
        canvas.drawLine(mMainRectF.right, mMainRectF.bottom, mMainRectF.right - 15f, mMainRectF.bottom + 10f, mPaintAxis);
        canvas.drawLine(mMainRectF.right, mMainRectF.bottom, mMainRectF.right - 15f, mMainRectF.bottom - 10f, mPaintAxis);
        // X标签
        final float textX = mMainRectF.right + 15f;
        final float textY = mMainRectF.bottom + 0.5f * PaintUtils.getTextBoundsHeight(mPaintAxisLabel, mAxisLabelX);
        canvas.drawText(mAxisLabelX, textX, textY, mPaintAxisLabel);
    }

    /**
     * 绘制Y坐标轴
     */
    private void drawAxisY(Canvas canvas) {
        // Y轴线
        canvas.drawLine(mMainRectF.left, mMainRectF.bottom, mMainRectF.left, mMainRectF.top, mPaintAxis);
        // Y轴箭头
        canvas.drawLine(mMainRectF.left, mMainRectF.top, mMainRectF.left - 10f, mMainRectF.top + 15f, mPaintAxis);
        canvas.drawLine(mMainRectF.left, mMainRectF.top, mMainRectF.left + 10f, mMainRectF.top + 15f, mPaintAxis);
        // Y标签
        final float textX = mMainRectF.left - 0.5f * PaintUtils.getTextBoundsWidth(mPaintAxisLabel, mAxisLabelY);
        final float textY = mMainRectF.top - 15f;
        canvas.drawText(mAxisLabelY, textX, textY, mPaintAxisLabel);
    }

    /**
     * 绘制X轴刻度、竖直网格线和刻度标签
     */
    private void drawGridsX(Canvas canvas) {
        final int times = (int) Math.ceil((mMainRectF.left - mAnchorX) / mGridsBasicX);
        int index = mAxisScalesX.index + times;
        float currentX = mAnchorX + times * mGridsBasicX;
        final int count = (int) Math.ceil((mMainRectF.right - 50f - currentX) / mGridsBasicX);
        final int width = mAxisScalesX.getMaximumWidth(mPaintScalesLabel, index, index + count);
        final int interval = Math.max(1, (int) Math.ceil(2 * width / mGridsBasicX));
        int tag = index % interval;
        while (currentX <= mMainRectF.right - 50f) {
            // 竖直网格线
            canvas.drawLine(currentX, mMainRectF.bottom, currentX, mMainRectF.top + 25f, mPaintGrids);
            // X轴刻度
            canvas.drawLine(currentX, mMainRectF.bottom, currentX, mMainRectF.bottom - 15f, mPaintAxis);
            // X轴刻度标签
            if (index >= 0 && index < mAxisScalesX.count) {
                if (tag == 0) {
                    final String text = mAxisScalesX.getText(index);
                    final float textX = currentX - 0.5f * PaintUtils.getTextBoundsWidth(mPaintScalesLabel, text);
                    final float textY = mMainRectF.bottom + PaintUtils.getTextBoundsHeight(mPaintScalesLabel, text) + 15f;
                    canvas.drawText(text, textX, textY, mPaintScalesLabel);
                }
                tag = ++tag % interval;
            }
            ++index;
            currentX += mGridsBasicX;
        }
    }

    /**
     * 绘制Y轴刻度、水平网格线和刻度标签
     */
    private void drawGridsY(Canvas canvas) {
        final int times = (int) Math.ceil((mAnchorY - mMainRectF.bottom) / mGridsBasicY);
        int index = mAxisScalesY.index + times;
        float currentY = mAnchorY - times * mGridsBasicY;
        final int height = (int) Math.ceil(mPaintScalesLabel.getFontMetrics().bottom - mPaintScalesLabel.getFontMetrics().top);
        final int interval = Math.max(1, (int) Math.ceil(2 * height / mGridsBasicY));
        int tag = index % interval;
        while (currentY >= mMainRectF.top + 50f) {
            // 水平网格线
            canvas.drawLine(mMainRectF.left, currentY, mMainRectF.right - 25f, currentY, mPaintGrids);
            // Y轴刻度
            canvas.drawLine(mMainRectF.left, currentY, mMainRectF.left + 15f, currentY, mPaintAxis);
            // Y轴刻度标签
            if (index >= 0 && index < mAxisScalesY.count) {
                if (tag == 0) {
                    final String text = mAxisScalesY.getText(index);
                    final float textX = mMainRectF.left - PaintUtils.getTextBoundsWidth(mPaintScalesLabel, text) - 15f;
                    final float textY = currentY + 0.5f * PaintUtils.getTextBoundsHeight(mPaintScalesLabel, text);
                    canvas.drawText(text, textX, textY, mPaintScalesLabel);
                }
                tag = ++tag % interval;
            }
            ++index;
            currentY -= mGridsBasicY;
        }
    }


    /**
     * 设置坐标轴颜色
     *
     * @param color 颜色 argb
     */
    public void setAxisColor(@ColorInt int color) {
        if (mAxisColor != color) {
            mAxisColor = color;
            configPaint(PaintType.AXIS);
            invalidate();
        }
    }

    /**
     * 设置坐标轴厚度
     *
     * @param thickness 厚度 px
     */
    public void setAxisThickness(@Px int thickness) {
        if (mAxisThickness != thickness) {
            mAxisThickness = thickness;
            configPaint(PaintType.AXIS);
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置网格X轴大小
     *
     * @param sizeX 大小 px
     */
    public void setBasicGridX(@Px int sizeX) {
        if (mGridsBasicX != sizeX) {
            mGridsBasicX = sizeX;
            mGridsBasicKeepX = mGridsBasicX;
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置网格Y轴大小
     *
     * @param sizeY px
     */
    public void setBasicGridY(@Px int sizeY) {
        if (mGridsBasicY != sizeY) {
            mGridsBasicY = sizeY;
            mGridsBasicKeepY = mGridsBasicY;
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置网格颜色
     *
     * @param color 颜色 argb
     */
    public void setGridsColor(@ColorInt int color) {
        if (mGridsColor != color) {
            mGridsColor = color;
            configPaint(PaintType.GRIDS);
            invalidate();
        }
    }

    /**
     * 设置网格厚度
     *
     * @param thickness 厚度 px
     */
    public void setGridsThickness(@Px int thickness) {
        if (mGridsThickness != thickness) {
            mGridsThickness = thickness;
            configPaint(PaintType.GRIDS);
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置X轴标签文本
     *
     * @param labelX 标签文本
     */
    public void setAxisLabelX(String labelX) {
        if (!TextUtils.equals(mAxisLabelX, labelX)) {
            mAxisLabelX = labelX;
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置Y轴标签文本
     *
     * @param labelY 标签文本
     */
    public void setAxisLabelY(String labelY) {
        if (!TextUtils.equals(mAxisLabelY, labelY)) {
            mAxisLabelY = labelY;
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置坐标轴标签文本颜色
     *
     * @param color 颜色 argb
     */
    public void setAxisLabelTextColor(@ColorInt int color) {
        if (mAxisLabelTextColor != color) {
            mAxisLabelTextColor = color;
            configPaint(PaintType.AXIS_LABEL);
            invalidate();
        }
    }

    /**
     * 设置坐标轴标签文本字体大小
     *
     * @param textSize 字体大小 px
     */
    public void setAxisLabelTextSize(@Px int textSize) {
        if (mAxisLabelTextSize != textSize) {
            mAxisLabelTextSize = textSize;
            configPaint(PaintType.AXIS_LABEL);
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置坐标轴标签文本字体
     *
     * @param typeface 文本字体
     */
    public void setAxisLabelTypeface(Typeface typeface) {
        mAxisLabelTypeface = typeface;
        configPaint(PaintType.AXIS_LABEL);
        invalidate();

    }

    /**
     * 设置X轴刻度列表
     *
     * @param scaleList 标签文本
     */
    public void setAxisScalesX(AxisScales scaleList) {
        mAxisScalesX = scaleList;
        requestLayout();
        invalidate();
    }

    /**
     * 设置Y轴刻度列表
     *
     * @param scaleList 标签文本
     */
    public void setAxisScalesY(AxisScales scaleList) {
        mAxisScalesY = scaleList;
        requestLayout();
        invalidate();
    }


    /**
     * 设置刻度列表标签文本颜色
     *
     * @param color 颜色 argb
     */
    public void setAxisScaleLabelTextColor(@ColorInt int color) {
        if (mAxisScalesLabelTextColor != color) {
            mAxisScalesLabelTextColor = color;
            configPaint(PaintType.SCALE_LABEL);
            invalidate();
        }
    }

    /**
     * 设置刻度列表标签文本字体大小
     *
     * @param textSize 字体大小 px
     */
    public void setAxisScaleLabelTextSize(@Px int textSize) {
        if (mAxisScalesLabelTextSize != textSize) {
            mAxisScalesLabelTextSize = textSize;
            configPaint(PaintType.SCALE_LABEL);
            requestLayout();
            invalidate();
        }
    }

    /**
     * 设置刻度列表标签文本字体
     *
     * @param typeface 文本字体
     */
    public void setAxisScaleLabelTypeface(Typeface typeface) {
        mAxisScalesLabelTypeface = typeface;
        configPaint(PaintType.SCALE_LABEL);
        invalidate();
    }

    /**
     * 重置网格大小
     */
    public void resetGridSize() {
        mGridsBasicX = mGridsBasicKeepX;
        mGridsBasicY = mGridsBasicKeepY;
        requestLayout();
        invalidate();
    }

    /**
     * 重置锚点
     */
    public void resetAnchorPoint() {
        mAnchorX = mMainRectF.left + 0.5f * mGridsBasicX;
        mAnchorY = mMainRectF.bottom - 0.5f * mGridsBasicY;
        invalidate();
    }
}